/*************************************************************************
> File Name: ctc_func.h
> Revised: Gaoxinglong
> Mail: gaoxinglong9999@163.com
> Created Time: Sat 05 Sep 2015 12:37:39 PM CST
************************************************************************/
#pragma warning(disable:4996)
#ifndef CTC_FUNC_H
#define CTC_FUNC_H
#include<iostream>
#include<vector>
#include <cstdint>
#include <unordered_map>
using namespace std;


template<bool B> class KaldiCompileTimeAssert { };
template<> class KaldiCompileTimeAssert<true> {
public:
	static inline void Check() { }
};

#define KALDI_COMPILE_TIME_ASSERT(b) KaldiCompileTimeAssert<(b)>::Check()

#define KALDI_ASSERT_IS_INTEGER_TYPE(I) \
  KaldiCompileTimeAssert<std::numeric_limits<I>::is_specialized \
                 && std::numeric_limits<I>::is_integer>::Check()

#define KALDI_ASSERT_IS_FLOATING_TYPE(F) \
  KaldiCompileTimeAssert<std::numeric_limits<F>::is_specialized \
                && !std::numeric_limits<F>::is_integer>::Check()

#define ASSERT_MEMO(ptr) do {\
	if(ptr == nullptr) fprintf(stderr, "%s:%d:Memory error\n", __FILE__, __LINE__);\
} while (0);

//////////////////////        typename definition              ///////////////////////////////
typedef std::vector<double> DoubleVector;
typedef std::vector<int> IntVector;
typedef std::vector<DoubleVector> DoubleMatrix;
typedef std::vector<IntVector> IntMatrix;
typedef std::unordered_map<std::string, IntVector*> LabelChunk;
typedef std::unordered_map<std::string, DoubleMatrix*> FeatureChunk;



int ReadKaldiLabels(const char* label_file, 
	std::unordered_map<std::string, std::vector<int>* >* label_out);
int ReadKaldiFeatures(const char* feature_file, std::unordered_map<std::string, 
	DoubleMatrix* >* feature_out);

void ReadStandardVector(std::ifstream& is, std::vector<double>* v_out);

int SplitString(const char* in, std::vector<std::string>& out, const char* delim);
int IsStringIn(const char* in, const char* delim);
uint64_t Roundup2TwoExponetial(uint64_t n);


void FreeFeatures(FeatureChunk* feature);

void FreeLabels(LabelChunk* labels);

double** CopyDoubleMatrix2Simple(const DoubleMatrix* src_mat, int& rows, int& cols);




void resultout(float** grad, int array_n, int array_m, float llforward, int step, int seq[], int seqLen, float** params, float llbackward);
double** CopyVector2TwoDimMatrix(int64_t rows, int64_t cols, std::vector<double>& src_mat);

int** CopyVector2TwoDimMatrix(int64_t rows, int64_t cols, std::vector<int>& src_mat);
void resultout1(float** grad, int array_n, int array_m, float llforward, int step, int seq[], int seqLen, float** params);

void resultout(float** grad, int array_n, int array_m, float llforward, int step, int seq[], int seqLen, float** params, float llbackward);
//sub_max() is func used to find the max value of every column,
//and subtract the max value from the Matrix
void sub_max(float **(&params), int array_n, int array_m);

//array_exp() is func used to get the exp value of every element of the Matrix
void array_exp(float **(&params), int array_n, int array_m);

//array_sum_column() is func used to sum every column of the Matrix and put the summation of the column to
//the parameter sum_of_column.
void array_sum_column(float(**params), float *(&sum_of_column), int array_n, int array_m);

//array_norm() is func used to normalise the Matrix in the column direction
void array_norm(float **(&params), int array_n, int array_m);

//array_sum_sincolumn() is func used to sum the Matrix in the column direction,
//but you have to declare the num of the column and the beginning and ending of 
//the summation
float array_sum_sincolumn(float **array, int num_of_columns, int t = 0, int start = 0, int end = 0);

//delete_bidimen_array() is the func used to delete the two dimension dynamic ptr_
void delete_bidimen_array(float **array, int n, int m);

//ctc_loss() is func used to calculate the ctcloss and the grad of the ctc NN
float ctc_loss(float **(&grad), float **params, int array_n, int array_m, int *seq, int seqLen, int blank = 0, bool is_prob = true);

//best_path_decode() is func used to decode the NN using the best-path method
void best_path_decode(float **(&params), int array_n, int array_m, vector<int> &seq, int blank = 0);

#endif
